<?
package("japhax.sql");

import("japhax.sql.Database");

/**
 * $Id: Access.php 9 2010-04-25 05:02:05Z bsdlite $
 *
 * Class Access provides a simple interface for connecting to an ODBC datasource (that is, an Access Database File)
 * In order to use this class, you must create an ODBC DSN for your database file, which, if you are
 * using this class, will probably already be common knowledge for you. If not, try googling for a
 * quick tutorial on it, or open your control panel and double click "ODBC Data Sources".
 *
 * This class is a little different, in that it will NOT automatically connect to the datasource
 * when it is instantiated, instead, there is a seperate method for connection.
 *
 * My main reason for doing it this way is two fold:
 *
 * 1) Should the information passed to the constructor be incorrect, it will not foil the entire
 *    execution flow of the script, but will allow for easier exception handling.
 *
 * 2) If you needed to delete the reference to the ODBC/Access datasource before all of the references
 *    to the object were finished, you would have a more unified way of recreating the connection. If
 *    the connection mechanism were in the constructor, the only way to reconnect to the database would
 *    be to reinstatiate the class, which is not always a good idea on the fly, and is never a good idea
 *    if you are trying to keep objects and memory usage to a minimum.
 *
 * @author <a href="mailto:gantt@cs.montana.edu">Ryan Gantt</a>
 * @version $Revision: 9 $ $Date: 2010-04-25 05:02:05 +0000 (Sun, 25 Apr 2010) $
 */
 
class Access extends Database implements SQL
{
    /**
     * Datasource name for the ODBC/Access database file
     *
     * @access protected
     * @var
     */
    protected $dsn;
    
    /**
     * Username for the current DSN
     *
     * @access protected
     * @var
     */
    protected $user;
    
    /**
     * Password for the current DSN
     *
     * @access protected
     * @var
     */
    protected $pass;
    
    /**
     * Connection ID for the current state. 
     * Queries can only be executed if this has been 'instantiated'
     *
     * @access protected
     * @var
     */
    protected $connection;
    
    /**
     * The ID for the current query. 
     * This is automatically 'instantiated' when you run a query.
     *
     * @access protected
     * @var
     */
    protected $current;
    
    /**
     * Array to be populated on a call to fetchArray().
     * @see fetchArray()
     *
     * @access protected
     * @var
     */
    protected $retArray = array();
    
    /**
     * Unified constructor for Access.
     * Takes a DSN, username, and password as parameters, but the password can be
     * omitted if there is no password set on the ODBC Datasource.
     *
     * This will NOT create a connection to the database, only load up the user variables.
     * Connections can be made fromt the connect() method once Access has been instantiated.
     */
    public function __construct( $dsn, $user, $pass = '' )
    {
           $this->dsn = $dsn;
           $this->user = $user;
           $this->pass = $pass;
    }
    
    /**
     * Creates a new ODBC/Access database connection
     * Uses the current DSN/User/Pass info to make the connection
     * Will throw an exception is there is an error in the connection
     *
     * @access public
     * @throws DatabaseException
     */
    public function connect( Address $address="", $user="", $pass="" ) {
        $this->connection = odbc_connect( $this->dsn , $this->user, $this->pass ); 
        if ( !$this->connection )
        { 
            throw new Exception("Could not connect to ODBC data source!: " . odbc_error() . ", " . odbc_errormsg() );
        } 
    }
    
    /**
     * Returns true if the connection has been.. well.. connected.
     *
     * @access public
     * @return boolean ture iff the dsn is connected
     */
    public function is_connected()
    {
        return isset($this->connection) ? TRUE : FALSE;   
    }
    
    /**
     * Execute a predefined query on the datasource.
     * Will throw a DatabaseException if there is an error with the query.
     *
     * @access public
     * @return ODBC An executed OCDBC query / result set
     * @throws DatabaseException
     * @param query Query String to run against the ODBC/Access datasource
     */
    public function query( $query )
    {
        if ( !$this->isConnected() )
        {
            throw new Exception("Could not execute query!: " . odbc_error() . ", " . odbc_errormsg() );
        }
        else
        {
            return odbc_exec( $this->connection, $query );
        }
    }

    /**
     * Retunrs the result set generated by the passed query as a good 'ol array.
     *
     * @access public
     * @param handle The executed query / result set
     * @return Object[] fetched array
     */
    public function fetch_array( $handle )
    {
        static $count = 0;
        $fields = $this->getNumFields();

        if( odbc_fetch_row( $handle ) )
        {
            foreach( $fields as $key )
            {
                $this->retArray[] = odbc_result( $handle, $key );
            }
            $count++;
        }
        return $this->retArray;
    }

    /**
     * Will get the number of fields that is being returned by the passed query.
     * Note: This is different from getNumRows, as it returns 'horizontally'.
     *
     * @access public
     * @param handle The executed query / result set
     * @return int the number of fields fetched by the query
     */
    public function num_fields()
    {
        return odbc_num_fields( $this->handle );
    }

    /**
     * Will return the number of rows that are being returned by the passed query
     * Note: This is different from getNumFields, as it returns 'vertically'.
     *
     * @access public
     * @param handle The executed query / result set
     * @return int the number of rows fetched by the query
     */
    public function num_rows( $handle )
    {
        return odbc_num_rows( $handle );
    }

    public function fetch_object( $handle )
    {
    	return;
    }

    /**
     * Turns the current access point to the ODBC/Access datasource into a null reference.
     *
     * @access public
     */
    public function close()
    {
        odbc_close( $this->connection );    
    }

	public function select_db( $db )
	{
		return;
		# This method only exists for conformity -- There are no freakin' databases in ODBC
		# and the DSN has already been dealt with
	}
}
?>
